#!/usr/bin/python

# -*- coding: utf-8 -*-

# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#
#  This program is free software; you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation; either version 2 of the License, or (at
#  your option) any later version.
#
#  This program is distributed in the hope that it will be useful, but
#  WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
#  General Public License for more details.
#
#  You should have received a copy of the GNU General Public Licensef along
#  with this program; if not, write to the Free Software Foundation, Inc.,
#  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
#
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


import sys
import time
import math
from qt import *
 
#
# in devicesconfig.py there are all classes which holds the gpib/visa commands for the different instruments
# you have to modify this file to add instruments
# !!!!!!!!!!!!!!!!!!! please read the ReadMe !!!!!!!!!!!!!!!!!!!!!!!!!!1
#
# Classes: 	allDevices:	holds a list with all devices pyvlab should know
#		abstractDevice:	is the prototyp to talk with instruments, DO NOT CHANGE it, 
#				except you know what your are doing!
#		some devices:	devices pyvLab can talk with
#
 
class allDevices(object):
	def __init__(self):
		#print "allDevies"
		#Comment full lines to disable some devices you do not use!
		self.devices=(	"none", #Do not remove the "no-device" device
				"eggtimer", #Standby Time Device, wait n seconds before proceeding
				"constant",
				"counter",
				"yValue",
				"integral",
				"stopatintegral",
				"fetchdevice", #Reads with :fetch?, supports Keithley 2000, some picometers...
				"keithley2400", #Keithley2400  1muA current protection, set volt, read current, form Volt,Curr 
				"keithley6487", #Keithley6548, can change voltage, read current
				"keithley6485", #Keithley6545 reads current
				"agilentDCoutput", #Agilent E3646A, set voltage
				"agilentCurroutput", #Agilent E3646A, set current
				"smpPower", #Rohde&Schwarz Signalgenerator SMP, sets Power
				"smpFreq",  #Rohde&Schwarz Signalgenerator SMP, sets Freq
				"networkanalyzerspectrum", #Rohde&Schwarz Network Analyzer: Reads Spectrum
				"networkanalyzermarker", #Rohde&Schwarz Network Analyzer: Reads Marker
				"heaterNeocera", #Heater
				"heaterNeoceraControl", #Heater
				"heaterNeoceraControl2", #Heater
				"keithley213port1", # Leithley 213 Port 1 (of 4 output ports)
				"keithley213port2",
				"keithley213port3",
				"keithley213port4"
				#"testKeithley" #Test for heater
				) 
		
	def all(self):
		return self.devices
	
	
#Don't change this device, create a new Subclass of abstractDevice instead
class abstractDevice(object):
	def __init__(self):
		self.typ="abstract" #Devies is nothing
		self.name="(abstract)"
		self.steppos=0.0
		self.rawdata=[]
		self.begin=0.0
		self.end=0.0
		self.steps=0.0
		self.init=()
		self.finish=()
		self.step=()
		self.resultform="unknown"
		self.canAveraging=False #Take more measurement points and make average
		self.mode=0 # 0=nothing 1=|... 2=-->
		self.description="(no desciption)"
		self.plotLastXValue=0
		self.plotLastYValue=0
		self.plotYValue=0
		self.plotXValue=0
		self.plotIntegral=0
		
		
	def splitData(self,newData):
		data=[]
		#print "Beginn getdata"
		for x in newData:
                        if x.rfind(";")>-1: x=x.replace(";",",")
			tmp=x.split(',')
			#print tmp
			#if len(tmp)==1: tmp=x.split(';')
			
			while len(data)<len(tmp):
				data.append(0)
				
			i=0
			while i<len(tmp):
				
				#Remove Textparts
				#tmp[i]=tmp[i]+"Ampere"
				#print tmp[i]
				#print tmp[i][len(tmp[i])-1]
				if len(tmp[i])>0:
					while tmp[i][len(tmp[i])-1].isdigit()==False:
						tmp[i]=tmp[i][:-1]
						tmp[i].strip()
						tmp[i].rstrip()
						#print tmp[i]
						if len(tmp[i])==0:
							tmp[i]=0
							break
					#print tmp[i]
					data[i]=float(data[i])+float(tmp[i])
					#print tmp[i], data[i]
				else: data[i]=0
				i+=1
		
		#print "Mitte getdata"
		n=len(self.rawdata)
		i=0
		while i<len(data):
			data[i]=float(data[i]/n)
			i+=1
			
		self.rawdata=[]
		
		data2=[]
		if len(data)==0:	
			data2.append(self.steppos)
		for x in data:
			data2.append(x)
		#print "Ende getdata"
		return data2
		
	def getData(self):
		return (self.splitData(self.rawdata),) # List with one measurement data!
	
	def read(self):
		return ":read?"
	
	def getInit(self):
		#print "init: "+self.init
		return self.init
	
	def getFinish(self):
		return self.finish
	
	def getStep(self,value):
		return self.step
	
	def setPlotValues(self,plotLastXValue,plotLastYValue,plotYValue,plotXValue,plotIntegral):
		self.plotLastXValue=plotLastXValue
		self.plotLastYValue=plotLastYValue
		self.plotYValue=plotYValue
		self.plotXValue=plotXValue
		self.plotIntegral=plotIntegral
	
	def getDataString(self):
		return self.rawdata
	
	def getStepPos(self):
		return self.steppos
	
	def setStepPos(self,pos):
		self.steppos=pos
		
	def incStepPos(self,pos):
		self.steppos+=pos
		
	def addRawData(self,data):
		self.rawdata.append(data)
		
	#Test if Data is OK, e.g if heater temperature already reached,
	#if not a new reading will be made and asked again
	def isDataOK(self,data):
		#return 0 if data is OK, else return milliseconds to wait
		#print "New Data: "+data," Steppos: ",self.steppos
		return 0
	
class none(abstractDevice):
	def __init__(self):
		abstractDevice.__init__(self)
		self.typ="none" #Devies is nothing
		self.classname="none" #Do not change
		self.name="(none)"
		self.description="no device"
	
	
#Virtual device, just waites, no measurement data
class eggtimer(abstractDevice):
	def __init__(self):
		abstractDevice.__init__(self)
		self.typ="vsrw" #virtual Device, no GPIB Address
		self.classname="clock"
		self.init=()
		self.finish=() #"*rst",) #:trace:clear",":feed:control next")
		self.name="Standby Time (secs)"
		self.waittime=()
		self.canAveraging=False
		self.resultform="elapsed time"
		self.description="Wait for n seconds"
		#self.time=QTime()
		self.elapsedtime=QTime()
		#self.time.start()
		self.elapsedtime.start()
		self.counter=0
		
	def getInit(self):
		self.elapsedtime.restart()
		#self.time.restart()
		self.counter=0
		return self.init
		
	def read(self):
		self.counter+=1
		self.steppos=self.begin
            	print str(self.plotLastXValue)+" "+str(self.plotLastYValue)+" "+str(self.plotXValue)+" "+str(self.plotYValue)+" "+str(self.plotIntegral)
		elapsed=self.elapsedtime.elapsed()
		t=(self.counter*self.steppos-(elapsed+2.0)/1000.0)
		print "Sleeping ",(t),elapsed
		if (t>0): 
			time.sleep(t)
		#self.time.restart()
		return str(self.elapsedtime.elapsed()/1000.0)

	
class counter(abstractDevice):
	def __init__(self):
		abstractDevice.__init__(self)
		self.typ="vrw" #virtual Device, no GPIB Address
		self.classname="counter"
		self.init=()
		self.finish=()
		self.name="Counter"
		self.waittime=()
		self.canAveraging=False
		self.resultform="Number of counts"
		self.description="Counts..."
		self.mycounter=0
		
	def getInit(self):
		self.mycounter=self.begin-1
		return self.init
		
	def read(self):
		self.mycounter+=1
		#self.steppos=self.begin
		return str(self.mycounter)
		
	
class constant(abstractDevice):
	def __init__(self):
		abstractDevice.__init__(self)
		self.typ="vsrw" #virtual Device, no GPIB Address
		self.classname="constant"
		self.init=()
		self.finish=() #"*rst",) #:trace:clear",":feed:control next")
		self.name="Constant"
		self.waittime=()
		self.canAveraging=False
		self.resultform="Constant"
		self.description="Returns constant"
		
	def getInit(self):
		self.mycounter=0
		return self.init
		
	def read(self):
		self.steppos=self.begin
		return str(self.begin)
	
	
class yValue(abstractDevice):
	def __init__(self):
		abstractDevice.__init__(self)
		self.typ="vsrw" #virtual Device, no GPIB Address
		self.classname="yValue"
		self.init=()
		self.finish=() #"*rst",) #:trace:clear",":feed:control next")
		self.name="Stop at yValue"
		self.waittime=()
		self.canAveraging=False
		self.resultform="lastYValue"
		self.description="Stops measurement when reaching a certain y-Value"
		
	def read(self):
		if (self.plotYValue>=self.begin):
			x="STOPNOW"
			print "do stop"
		else:
			x=""	
		self.steppos=self.begin
		return x+str(self.plotLastYValue)
		
	
class stopatintegral(abstractDevice):
	def __init__(self):
		abstractDevice.__init__(self)
		self.typ="vsrw" #virtual Device, no GPIB Address
		self.classname="integral"
		self.init=()
		self.finish=() #"*rst",) #:trace:clear",":feed:control next")
		self.name="Stop at Integralvalue"
		self.waittime=()
		self.canAveraging=False
		self.resultform="Integral"
		self.description="Stops measurement when reaching a certain inmtegral-Value"
		
	def read(self):
		if (self.plotIntegral>self.begin):
			x="STOPNOW"
		else:
			x=""
			
		self.steppos=self.begin
		return x+str(self.plotIntegral)
	
	
class integral(abstractDevice):
	def __init__(self):
		abstractDevice.__init__(self)
		self.typ="vr" #virtual Device, no GPIB Address
		self.classname="integral"
		self.init=()
		self.finish=() #"*rst",) #:trace:clear",":feed:control next")
		self.name="Integralvalue"
		self.waittime=()
		self.canAveraging=False
		self.resultform="Integral"
		self.description="Returns integral-Value of the graph"
		
	def read(self):
		self.steppos=self.begin
		return str(self.plotIntegral)
	
#Easy device, some instruments (like Keithley 2000) support the fetch? command
#when asked, they return just their display value....
#you can start with copying this code, when you like to add a new instrument
class fetchdevice(abstractDevice):
	def __init__(self):
		abstractDevice.__init__(self)
		self.classname="fetchdevice"
		self.typ="r" #Devies reads only
		self.init=()   #":*rst",":init")
		self.finish=() #"*:rst",)
		self.name=":Fetch? compatible device"
		self.resultform="display value"
		self.description="Get display value from fetch-compatible device"
		self.canAveraging=True
		
	#overwrite the abstracDevice read-function, because it would ask ":read?" instead of ":fetch?"
	def read(self):
		return ":fetch?"
	
	
#More complex device. Set a source voltage, read current.
#The data read out (e.g. "1.0,0.54365A") is splitted by the getdata-function (of abstractDevice) automatically
class keithley2400(abstractDevice):
	def __init__(self):
		abstractDevice.__init__(self)
		self.typ="rw" #Devies reads and writes
		self.classname="keithley2400" #":SENS:CURR:PROT 0.000001",
		self.init=(":SOUR:FUNC VOLT",":SOUR:CLE:AUTO OFF",":SENS:FUNC 'CURR:DC'",":SOUR:VOLT:MODE FIX",":FORM:ELEM VOLT,CURR",":OUTP:STAT ON")
		self.finish=()
		self.name="Keithley 2400"
		self.resultform="voltage,current"
		self.description="Sets source voltage, reads current"#, 1muA current protection"
		self.canAveraging=True
		
	#Change source voltage to value
	def getStep(self,value):
		s=(":SOUR:VOLT "+str(value),)
		return s
	
	#device is read out with ":read?" (standard)


#More complex device. Set a source voltage, read current.
#The data read out (e.g. "0.54365A,1.0") is splitted by the getdata-function (of abstractDevice) automatically
class keithley6487(abstractDevice):
	def __init__(self):
		abstractDevice.__init__(self)
		self.typ="rw" #Devies reads and writes
		self.classname="keithley6487"
		#"SOUR:VOLT:ILIM1e-6",
                self.init=("RANG:AUTO off","SYST:ZCH OFF","FORM:ELEM read,vso","SOUR:VOLT:ILIM 2.5e-5","SOUR:VOLT:STAT ON","INIT")
		self.finish=() #"SOUR:VOLT 0",)
		self.name="Keithley 6487 (25mu Prot)"
		self.resultform="current,voltage"
		self.description="Sets source voltage, reads current, 25muA current protection"
		self.canAveraging=True
		
	#change source voltage
	def getStep(self,value):
		s=("SOUR:VOLT "+str(value),)
		return s
	
	#device is read out with ":read?" (standard)
		
		

class keithley6485(abstractDevice):
	def __init__(self):
		abstractDevice.__init__(self)
		self.typ="r" #Devies reads and writes
		self.classname="keithley6485"
                self.init=("RANG:AUTO off","SYST:ZCH OFF","FORM:ELEM read","INIT")
		self.finish=()
		self.name="Keithley 6485"
		self.resultform="current"
		self.description="reads current"
		self.canAveraging=True
	

#A signal generator, here power is set
class smpPower(abstractDevice):
	def __init__(self):#
		abstractDevice.__init__(self)
		self.classname="smpPower"
		self.typ="w" #Devies writes only
		self.init=("*rst",":OUTP:STAT ON")
		self.finish=(":OUTP:STAT OFF",)
		self.name="R&S Signalgenerator (Power)"
		self.resultform="power" #the position value (that means the power in this case) will be save (because its a w-only instrument)
		self.description="Sets power of an R&S SMP02 (dB)"
		
	#change power
	def getStep(self,value):
		s=":SOUR:POW "+str(value)
		return (s,)	
		
		
#A signal generator, here frequency is set, see instrument above
class smpFreq(abstractDevice):
	def __init__(self):#
		abstractDevice.__init__(self)
		self.classname="smpFreq"
		self.typ="w" #Devies writes only
		self.init=("*rst",":OUTP:STAT ON")
		self.finish=(":OUTP:STAT OFF",)
		self.name="R&S Signalgenerator (Freq)"
		self.resultform="frequency" #the position value (that means the frequency in this case) will be save
		self.description="Sets frequency of an R&S SMP02 (MHz)"
		
	def getStep(self,value):
		s=":SOUR:FREQ "+str(value*1000000)
		return (s,)	

		
#Most complex instrument in here
#Reads out a whole spectrum
class networkanalyzerspectrum(abstractDevice):
	def __init__(self):#
		abstractDevice.__init__(self)
		self.classname="networkanalyzerspectrum"
		self.typ="r" #Just read out spectrum
		self.init=() 
		self.finish=() # No final commands
		self.name="R&S ZVC Spektrum" 
		self.resultform="freqency,Magnitude (dB),Phase,Real,Imaginary" 
		self.canAveraging=False #don't make multiple measurements
		self.description="Reads spectrum of a R&S ZVC"

	#Ask for the Y values (real+imaginary values) and the X Values (frequencies)
	def read(self):
                self.steppos=self.end*1.1 # Do not read Data twice (you can ignore this line)
		return ("TRAC? CH1DATA","TRAC:STIM? CH1DATA") 

	#Here we get not just one measurement point, but the whole spectrum
	#So we have to split the data into a list with all data points
	def getData(self):
		if len(self.rawdata[0])==0: 
			print "deviceConfig: ERROR: not data (in networkanalyzerspectrum getData)"
			return False

		#canAverage is false, so just Data in rawdata[0]
		#Y-Values then ,, then X-Values
		a=self.rawdata[0] # "1,2,3,,4,5,6"
		
		#Two read commands are sperated by ,, 
		b=a.split(",,") # "("1,2,3"),("4,5,6")
		
		#Split x measurement points (frequencies)
		xaxis=b[1].split(",") #X-measure points
		tmp=b[0].split(',') # Real and imaginary points

		
		i=0
		ix=0
		data=[]
		while i+1<len(tmp):
			#calculate of real and imaginary part magnitude, phase etc...
                        try:
                            magn=20*math.log10(math.hypot(float(tmp[i+1]),float(tmp[i])))
                            phase=math.tan(float(tmp[i+1])/float(tmp[i]))
                        except: 
				magn=0.0
				phase=0.0
                        res=[]
			#append results to ONE data set
                        res.append(str(xaxis[ix]))
                        res.append(str(magn))
                        res.append(str(phase))
                        res.append(str(tmp[i+0])) #real
                        res.append(str(tmp[i+1])) #imaginary

			data.append( res )
			i+=2
			ix+=1
			
		#Clear list of rawdata
		self.rawdata=[]
		return data # List with data sets!


#Just read out a marker of a network analyzer
class networkanalyzermarker(abstractDevice):
	def __init__(self):#
		abstractDevice.__init__(self)
		self.classname="networkanalyzermarker"
		self.typ="r" #Devies writes only
		self.init=(":CALC1:MARK1:FORM MDPH",)
		self.finish=()
		self.name="R&S ZVC Marker"
		self.canAveraging=False
		self.resultform="freqency,magnitude (dB),angle"
		self.description="Reads marker of an R&S ZVC"
		
	#read command
	def read(self):
		return (":CALC1:MARK1:x?",":CALC1:MARK1:y?") # ;V?
                #returns Frq, 0.0, dB, angle
		
	#extract the read out data
	def getData(self):
		l=self.splitData(self.rawdata)
		#l is now something like (including 0.0) l=(1.32,0.0,2.54,3.23)
		l2=[]
		l2.append(l[0])
		#l2.add(l[1] is 0.0 because of the 2 read-commands, which are seperated by ,,
		l2.append(l[2])
		l2.append(l[3])
		return (l2,)
		

class agilentDCoutput(abstractDevice):
	def __init__(self):#
		abstractDevice.__init__(self)
		self.classname="agilentDCoutput"
		self.typ="rw" #Devies writes only
		self.init=()
		self.finish=()
		self.name="Agilent E3646A (Voltage)"
		self.resultform="voltage,current" #the position value (that means the frequency in this case) will be save
		self.description="Sets voltage of an Agilent E3646A"
		
	def getStep(self,value):
		s="VOLT "+str(value)
		return (s,)	

        def read(self):
		return ("volt?;meas:curr?")

class agilentCurroutput(abstractDevice):
	def __init__(self):#
		abstractDevice.__init__(self)
		self.classname="agilentCurroutput"
		self.typ="rw" #Devies writes only
		self.init=()
		self.finish=()
		self.name="Agilent E3646A (Current)"
		self.resultform="current,volt" #the position value (that means the frequency in this case) will be save
		self.description="Sets current of an Agilent E3646A"
		
	def getStep(self,value):
		s="CURR "+str(value)
		return (s,)	
		
        def read(self):
		return ("meas:curr?;volt?")

		
class testKeithley(abstractDevice):
	def __init__(self):
		abstractDevice.__init__(self)
		self.typ="rw" #Devies reads and writes
		self.classname="testKeithley"
                self.init=("RANG:AUTO on","SYST:ZCH OFF","FORM:ELEM read,vso","SOUR:VOLT:ILIM 2.5e-5","SOUR:VOLT:STAT ON","INIT")
		self.finish=() #"SOUR:VOLT 0",)
		self.name="TestKeithley 6487 (Set to -1 to continue)"
		self.resultform="current,voltage"
		self.description="Sets source voltage, reads current, 25muA current protection"
		self.canAveraging=True
		
	#change source voltage
	def getStep(self,value):
		s=("SOUR:VOLT 0",)
		return s

	
	#device is read out with ":read?" (standard)

	#Test if Data is OK, e.g if heater temperature already reached,
	#if not a new reading will be made and asked again
	#Testfunction:Data is OK, when Voltage is (manually) sewt to 1
	def isDataOK(self,data):
		print "New Data: "+data," Steppos: ",self.steppos
		x=data.split(",")
		print "Current Voltage: ",x[1]
		if float(x[1])==-1.0: 
			return 0
		else:
			return 10000
		
		
class heaterNeocera(abstractDevice):
	def __init__(self):
		abstractDevice.__init__(self)
		self.typ="r" #Devies reads and writes
		self.classname="heaterNeocera"
                self.init=()
		self.finish=()
		self.name="Temperatur Controller (Neocera)"
		self.resultform="real temperature1,temperature2"
		self.description="reads temperature"
		self.canAveraging=False
		
	
	#read command
	def read(self):
		return ("QSAMP?1;","QSAMP?2;")

        def getData(self):
       		if len(self.rawdata)==0: 
        		print "deviceConfig: ERROR: not data (in Neocera getData)"
			return ((0,0),)

		#canAverage is false, so just Data in rawdata[0]
		#Y-Values then ,, then X-Values
		a=self.rawdata[0] # "1,2,3,,4,5,6"
                b=a.split(",,")
                if (len(b)<2):
                    return((0,0),)
                temp1=b[0].strip()
                temp2=b[1].strip()
                data=(temp1[:-2],temp2[:-2])
                self.rawdata=[]
                #print data
                return (data,)

class heaterNeoceraControl(heaterNeocera):
	def __init__(self):
		abstractDevice.__init__(self)
		self.typ="rw" #Devies reads and writes
		self.classname="heaterNeoceraControl"
		self.name="Heater (Neocera) [Just set]"
		self.resultform="real temperature1,temperature2"
		self.description="Sets temperature, reads temperature (just sets temperature)"

		
	#change source voltage
	def getStep(self,value):
		s=("SETP1,"+str(value)+";",)
		return s
               
class heaterNeoceraControl2(heaterNeoceraControl):
	def __init__(self):
		abstractDevice.__init__(self)
		self.typ="rw" #Devies reads and writes
		self.classname="heaterNeoceraControl2"
                self.init=()
		self.finish=()
		self.name="Heater (Neocera) [Waiting]"
		self.resultform="real temperature1,temperature2"
		self.description="Sets temperature, reads temperature (Waits till temperature reached)"
		self.canAveraging=False
		
            
	#Test if Data is OK, e.g if heater temperature already reached,
	#if not a new reading will be made and asked again
	def isDataOK(self,data):
		#print "New Data: ",data," Steppos: ",self.steppos
                b=data.split(",,")
                temp2=b[1].strip()
                temp2=temp2[:-2]
		diff=abs(float(temp2)-self.steppos)
		print "Diff: ",diff," Temp2: ",temp2
		#Weniger als 10% Abweichung?
		if diff<0.1*self.steppos: 
			return 0
		else:
			return 10000
		#return 0

		
#A Quad Voltage Source instrument (source/port 1)
class keithley213port1(abstractDevice):
	def __init__(self):#
		abstractDevice.__init__(self)
		self.classname="keithley213port1"
		self.typ="w" #Devies writes only
		self.init=()
		self.finish=()
		self.name="Keithley 213 Port 1"
		self.resultform="voltage" #the position value (that means the voltage in this case) will be save (because its a w-only instrument)
		self.description="Sets voltage on port 1"
		
	#change power
	def getStep(self,value):
		s="P1 C0 A1 V"+str(value)+" X"
		return (s,)	


#A Quad Voltage Source instrument (source/port 2)
class keithley213port2(abstractDevice):
	def __init__(self):#
		abstractDevice.__init__(self)
		self.classname="keithley213port2"
		self.typ="w" #Devies writes only
		self.init=()
		self.finish=()
		self.name="Keithley 213 Port 2"
		self.resultform="voltage" #the position value (that means the voltage in this case) will be save (because its a w-only instrument)
		self.description="Sets voltage on port 2"
		
	#change power
	def getStep(self,value):
		s="P2 C0 A1 V"+str(value)+" X"
		return (s,)


#A Quad Voltage Source instrument (source/port 3)
class keithley213port3(abstractDevice):
	def __init__(self):#
		abstractDevice.__init__(self)
		self.classname="keithley213port3"
		self.typ="w" #Devies writes only
		self.init=()
		self.finish=()
		self.name="Keithley 213 Port 3"
		self.resultform="voltage" #the position value (that means the voltage in this case) will be save (because its a w-only instrument)
		self.description="Sets voltage on port 3"
		
	#change power
	def getStep(self,value):
		s="P3 C0 A1 V"+str(value)+" X"
		return (s,)


#A Quad Voltage Source instrument (source/port 4)
class keithley213port4(abstractDevice):
	def __init__(self):#
		abstractDevice.__init__(self)
		self.classname="keithley213port4"
		self.typ="w" #Devies writes only
		self.init=()
		self.finish=()
		self.name="Keithley 213 Port 4"
		self.resultform="voltage" #the position value (that means the voltage in this case) will be save (because its a w-only instrument)
		self.description="Sets voltage on port 4"
		
	#change power
	def getStep(self,value):
		s="P4 C0 A1 V"+str(value)+" X"
		return (s,)

	    


